using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Autobot
{
    // This is basically a parser class for the algorithm.
    // Will update the algorithm and take appropriate action
    // to make the corrections.
    class RobotController
    {
        private AlgorithmResult currentResult;
        private Communicator server;
        
        // For file output
        string fileName;
        FileStream file;
        TextWriter textWriter;
        
        //Constructor
        public RobotController(Communicator com, string CommandLog)
        {
            fileName = CommandLog;

            // We cannot have a null controller
            if( com == null)
                throw(new Exception("RobotController has been given null communicator"));

            server = com;
            currentResult = null;

            // Try to open the file and if not, then whatever.
            try
            {
                file = new FileStream(fileName, FileMode.Create, FileAccess.Write);
            }
            catch (Exception e)
            {
                Console.WriteLine("Could not create command log\n");
                Console.WriteLine("Exception: " + e.Message);
                file = null;
            }

            // Next try and create the writer.
            try
            {
                textWriter = new StreamWriter(file);
            }
            catch (Exception e)
            {
                Console.WriteLine("Could not create command log\n");
                Console.WriteLine("Exception: " + e.Message);
            }
        }
        public void Update(GameTime gameTime, AlgorithmResult NewResult)
        {
            ParseResult(NewResult);
        }
        public void ParseResult(AlgorithmResult NewResult)
        {
            currentResult = NewResult;

            // If there is no result, then return
            if (currentResult == null)
                return;
          
            // Start a burst of messages. These will signify the client to wait until
            // the end burst message has been recieved before giving an update
            Message StartGroup = new Message();
            StartGroup.CreateBurstBeginMsg(1,currentResult.GetNumCommands());
            server.SendMessage(StartGroup.GetClientID(), StartGroup);

            for (int i = 0; i < currentResult.GetNumCommands(); i++)
            {
                // Init a new message that we will play with parameters
                Message newMessage = new Message();

                //////////////////////////
                AlgorithmCommand command = currentResult.GetCommand(i);
     
                switch (command.Action)
                {
                    case (int)AlgorithmAction.CHANGE_DIRECTION:

                        if(command.NumParams != 2)
                            return;
							
						newMessage.CreateMotorInvertMsg(1, (int)command.Params[0], (int)command.Params[1]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;

                    case (int)AlgorithmAction.DEC_SPEED:
                        if(command.NumParams!=2)
                            return;

                        // Add the message type and then we know if we are dealing
                        // with speed then we need to change the drive motor.
                        // Then we add the last param for how much.
                        newMessage.CreateMotorIncMsg(1, (int)MotorID.DRIVE, (int)(-command.Params[0]), (int)command.Params[1]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;

                    case (int)AlgorithmAction.INC_SPEED:
                        if(command.NumParams!=2)
                            return;

                        // Add the message type and then we know if we are dealing
                        // with speed then we need to change the drive motor.
                        // Then we add the last param for how much.
                        newMessage.CreateMotorIncMsg(1, (int)MotorID.DRIVE, (int)(command.Params[0]), (int)command.Params[1]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;

                    case (int)AlgorithmAction.SET_DRIVE_MOTOR:
                        if(command.NumParams!=2)
                            return;

                        // Set the drive motor to the desired value
                        newMessage.CreateMotorSetMsg(1, (int)MotorID.DRIVE, (int)(command.Params[0]), (int)command.Params[1]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;
                    
                    case (int)AlgorithmAction.SET_STEER_MOTOR:
                        if(command.NumParams!=2)
                            return;
                        
                        // Set the steering motor to the desired value
                        newMessage.CreateMotorSetMsg(1, (int)MotorID.STEERING, (int)(command.Params[0]), (int)command.Params[1]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;

                    case (int)AlgorithmAction.STOP:
                        if(command.NumParams!=1)
                            return;

                        // STOP THE CAR OH GAHD!!!
                        newMessage.CreateMotorSetMsg(1, (int)MotorID.DRIVE, (int)DriveMotorParams.STOP, (int)command.Params[0]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;

                    case (int)AlgorithmAction.TURN_LEFT:
                        if(command.NumParams!=2)
                            return;
                        
                        // We are dealing with the steering motor and negatively
                        // decrementing it to turn towards the left
						// I'm going to say negative for left and positive for right
                        newMessage.CreateMotorIncMsg(1, (int)MotorID.STEERING, -(int)(command.Params[0]), (int)command.Params[1]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;
						
                    case (int)AlgorithmAction.TURN_RIGHT:
                        if (command.NumParams != 2)
                            return;

                        // Again, increment the steering motor but in the other direction
                        // I'm going to say negative for left and positive for right
                        newMessage.CreateMotorIncMsg(1, (int)MotorID.STEERING, (int)command.Params[0], (int)command.Params[1]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;
                 
                    case (int)AlgorithmAction.PANIC:
                        if (command.NumParams != 1)
                            return;
                        
                        // The exact same as stop. Do we actually need this?
                        newMessage.CreateMotorSetMsg(1, (int)MotorID.DRIVE, (int)DriveMotorParams.STOP, (int)command.Params[0]);
                        server.SendMessage(newMessage.GetClientID(),newMessage);
                        break;
						
                    case (int)AlgorithmAction.NONE:
                        newMessage.CreateNoneMsg(1);
                        server.SendMessage(newMessage.GetClientID(), newMessage);
                        break;
                    default:
                        throw new Exception("Unknown Algorithm Action In controller");

                }
            }
            // End a burst of messages. These will signify the client to wait until
            // the end burst message has been recieved before giving an update
            Message EndGroup = new Message();
            EndGroup.CreateBurstEndMsg(1);
            server.SendMessage(EndGroup.GetClientID(), EndGroup);
        }
    }
}

